/*
 *  Copyright (C) 2007 Veit Wehner.
 *  All Rights Reserved.
 *
 *  This is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This software is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this software; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
 *  USA.
 */



 /** \file communication.c
  * \brief This file contains the functions 
  *  for the communication.
  * \author Veit Wehner <veit.wehner@gmail.com>
  */
         

#include "sw_update.h"

YANET_DECLARE_BUFFER(YanetRxBuffer, YANET_MAX_DATA);
YANET_DECLARE_BUFFER(YanetTxBuffer, YANET_MAX_DATA);
OS_DECLARE_EVENT(YanetRxBufferDone);
OS_DECLARE_EVENT(YanetTxBufferDone);


#if RECEIVE_PROTOCOLL == UART
OS_DECLARE_EXTERN_EVENT(UART_RX_EVENT);
#endif
#if RECEIVE_PROTOCOLL == ETHERNET
OS_DECLARE_EXTERN_EVENT(evHttpNotify);
#endif

/** This function initializes the YaNET Sockets.
*/
void init_yanet(){
  YANET_INIT_BUFFER(YanetTxBuffer);
  YANET_INIT_BUFFER(YanetRxBuffer);
  YanetRxBuffer.event   = &YanetRxBufferDone;
  YanetRxBuffer.appID   = 1;
}



/** This function initializes the the ethernet connection. 
*   The connection properties are stored in the communction member of the 
*   swupdate instance. That allows the swupdate process to use different 
*   protocols. 
*   @param *this swupdate pointer holding a reference to the communication instance.
*   @param *con Connection_t instance that should be initialized.
*   @param *tv TranceiveVector common data structure for RX and TX mode.
*/

#if RECEIVE_PROTOCOLL==ETHERNET
void init_ethernet(struct swupdate *this, Connection_t *con, TranceiveVector_t *tv){
  SHOW(init ethernet..);
  this->communice->con = con;
  this->communice->tv = tv;
  while (!(this->communice->con = tcp_passiveOpen(40, this->communice->tv))) {
    sleep(5000000);
  }
  clearEvent(this->communice->tv->notify);
  waitEvent(this->communice->tv->notify);
#if DEBUG
  printf("Connection established to %u.%u.%u.%u:%u\n",
	 this->communice->tv->ip[0], this->communice->tv->ip[1], this->communice->tv->ip[2], 
	 this->communice->tv->ip[3], this->communice->tv->port);
#endif
}
#endif



/** This function wrappes the send routine of the Yanet lib. 
*   @param *buf buffer containg the data
*   @param len length of the data packet 
*   @param *this swupdate* instance containing the communication partner 
*           node id.
*   @param broadcast Broadcast mode, not used by default.
*/

void transmit(unsigned char * buf, int len, struct swupdate *this, int broadcast){
  YanetTxBuffer.data = buf;
  YanetTxBuffer.datalen = len;
  YanetTxBuffer.event	= &YanetTxBufferDone;
  YanetTxBuffer.appID	= 1;
  if (broadcast == 1){
    YanetTxBuffer.flags   = YANET_BF_BROADCAST;
    YanetTxBuffer.bcg             = 0;
  }
  else{
    YanetTxBuffer.dst = this->communice->communication_partner;
    YanetTxBuffer.flags	= 0;
  }
  int err;
  err = YaNET_SendPacket(&YanetTxBuffer);
  if (err) {
    printf("Tx1 error %i\n", err);
  }
  waitEvent(&YanetTxBufferDone);
  if (YanetTxBuffer.state != YANET_BS_TX_OK) {
    printf("Tx2 error state %u\n", YanetTxBuffer.state);
  }
}



/**
 * This function transmits a packet
 * to the communication partner node via YaNET
 * if it is referenced by the write_word function of the swupdate object.
 * @param swupdate instance
 */
 
void yanet_write(struct swupdate* this){
#if ENCRYPTION==TEA
  unsigned char tmp[CHUNKSIZE];
  encode_packet(tmp, this->priv_data_buf, this->datalen);
  memcpy(this->priv_data_buf, tmp, sizeof(tmp));
  this->datalen = CHUNKSIZE;
#elif HASH_CHECKSUM == DAVIES_MEYER
  signature_packet(this, sig);
#endif
  transmit((unsigned char*)this->priv_data_buf, this->datalen, this, 0);
}



/**
 * This function transmits a short packet
 * to the communication partner node via YaNET
 * if it is referenced by the write_word function of the swupdate object.
 * @param swupdate instance
 */

void yanet_write_word(struct swupdate *this){
  transmit((unsigned char*)&this->priv_word, sizeof(this->priv_word), this, 0);
#if (DEBUG_LEVEL==2)
  SHOW(yanet packet transmitted);
#endif
}



/**
 * This function receives a packet via YaNET 
 * ( of word length, chunksize, whatever ).
 * @param swupdate instance
 */
 
void yanet_receive(){
  int err;
  err = YaNET_ReceivePacket(&YanetRxBuffer);
  if (err) {
    printf("RX error %i\n", err);
    sleep(1000000ul);
  }
  waitEvent(&YanetRxBufferDone);
  YanetRxBuffer.data[min(YanetRxBuffer.datalen, YanetRxBuffer.buflen)] = 0;
#if DEBUG_LEVEL == 2
  SHOW(received yanet packet);
#endif
}




/**
 * This function waits for a sync packet from the communication partner node
 * if it is referenced by the wait function of the swupdate object.
 * @param swupdate instance
 */
 
void wait_for_remote_node(struct swupdate *this){
  
#if (DEBUG_LEVEL==2)
  SHOW(waitingForPartner..);       
#endif
  yanet_receive();
  if (!strstr(YanetRxBuffer.data, "go on")){
    this->communice->acknowledgment = VERIFIED;
  }
  else if (!strstr(YanetRxBuffer.data, "encore une foi")){
    this->communice->acknowledgment = WRONG;
  }
}




/**
 * This function receives a packet ( containing a chunk of data ) 
 * from the communication partner node via YaNET
 * if it is referenced by the read function of the swupdate object.
 * @param swupdate instance
 */
 
void yanet_read(struct swupdate* this){
  yanet_receive();
#if ENCRYPTION 
  decode_packet(&YanetRxBuffer);
#endif
  this->datalen = YanetRxBuffer.datalen;
  memcpy (this->priv_data_buf, YanetRxBuffer.data, YanetRxBuffer.datalen);
#if HASH_CHECKSUM == DAVIES_MEYER
  signature_packet(this, remove_sig);
#endif
#if (DEBUG_LEVEL==2)
  int debug;
  SHOW(verbatim);
  for (debug=0; debug < this->datalen; debug++)
    SHOW_HEX(this->priv_data_buf[debug]);
#endif
}



/**
 * This function receives a short packet
 * from the communication partner node via YaNET
 * if it is referenced by the read_word function of the swupdate object.
 * @param swupdate instance
 */
 
void yanet_read_word(struct swupdate *this){
  yanet_receive();
  this->priv_word = *((int*)YanetRxBuffer.data);
}



/**
 * This function sends a sync packet to the communication partner node via radio 
 * if it is referenced by the sync function of the swupdate object.
 * @param swupdate instance
 */
 
void cc1100_sync(struct swupdate *this){
  unsigned char *buf = NULL;
  if (this->communice->acknowledgment == WRONG){
    buf = "encore une foi";
  }
  else if (this->communice->acknowledgment == VERIFIED){
    buf = "go on"; 
  }
#if DEBUG_LEVEL == 2
  SHOW(synchronize..);
  printf ("%s\n", buf);
#endif
  transmit(buf, sizeof(buf), this, 0);
}





/**
 * This function receives a short packet  
 * from the communication partner node via UART
 * if it is referenced by the read function of the swupdate object.
 * @param swupdate instance
 */
 
#if RECEIVE_PROTOCOLL==UART
void uart_read_word(struct swupdate *this){
  unsigned char buf[2];
  uart_getChars(this->communice->uart, buf, 2);
  this->priv_word = *((int*)buf);
#if (DEBUG_LEVEL==2)
  SHOW(uart read word done);
#endif
}



/**
 * This function receives a packet ( containing a chunk of data ) 
 * from the communication partner node via UART
 * if it is referenced by the read function of the swupdate object.
 * @param swupdate instance
 */
void uart_read(struct swupdate* this){
  uart_getChars(this->communice->uart, this->priv_data_buf, this->datalen);
}
#endif




/**
 * This function receives a packet
 * to the communication partner node via ethernet
 * if it is referenced by the write function of the swupdate object.
 * @param swupdate instance
 */
 
#if RECEIVE_PROTOCOLL==ETHERNET
void enc28j60_read2(struct swupdate *this){
  this->communice->tv->receive.level=0;
  waitEvent(this->communice->con->tv->notify);
  if (this->communice->tv->receive.level==2){
    this->priv_word =  *((int*)this->communice->tv->receive.data);
  }
  else{
#if (DEBUG == 2)
    int x;
    for (x=0; x<this->communice->tv->receive.level; x++)
      { SHOW_HEX(this->communice->tv->receive.data[x]);}
#endif       
    memcpy (this->priv_data_buf, this->communice->tv->receive.data, this->communice->tv->receive.level);    
  }
}
#endif



/**
 * This function sends a sync packet to the base station partner node via uart
 * if it is referenced by the sync function of the swupdate object.
 * @param swupdate instance
 */
#if RECEIVE_PROTOCOLL==UART
void uart_sync_pc(struct swupdate *this){
  if (this->communice->acknowledgment == VERIFIED){
    uart_sendStr(this->communice->uart,"go on\n"); 
  }
  else{
    uart_sendStr(this->communice->uart,"encore une foi\n"); 
  }
  
}
#endif





/**
 * This function sends a sync packet to the base station partner node via ethernet 
 * if it is referenced by the sync function of the swupdate object.
 * @param swupdate instance
 */
#if RECEIVE_PROTOCOLL==ETHERNET
void enc28j60_sync_pc(struct swupdate *this){
  sprintf(this->communice->con->tv->transmit.data, "go_on");
  tcp_send(this->communice->con, this->communice->tv->transmit.data, strlen(this->communice->tv->transmit.data));
}
#endif


